#include "udpServer.hpp"
#include <memory>
#include <unordered_map>
#include <unordered_set>
#include <fstream>
#include <cstdlib>
#include <cstring>
#include <cerrno>
using namespace std;
using namespace Server;
const string dictTXT = "./dict.txt";
unordered_map<string, string> dict;
void stringCut(string line, string *key, string *value, string target)
{
    size_t pos = line.find(target);
    if (pos != string::npos)
    {
        // 找到了
        *key = line.substr(0, pos);
        *value = line.substr(pos + 1, line.size() - 1);
    }
    return;
}
static void Lorddict()
{
    ifstream in(dictTXT, ios::binary);
    if (!in.is_open())
    {
        cerr << "open file error" << endl;
        exit(2);
    }
    string line;
    string key, value;
    while (getline(in, line))
    {
        stringCut(line, &key, &value, ":");
        dict.insert(make_pair(key, value));
    }
    cout << "lord success" << endl;
    in.close();
    return;
}
// demo1
void translation(int socketfd, string ip, uint16_t port, string messages)
{

    unordered_map<string, string>::iterator it = dict.find(messages);
    if (it != dict.end())
    {
        // 找到了，返回对应的英文
        string ret = (*it).second;
        struct sockaddr_in peer;
        bzero(&peer, sizeof peer);
        peer.sin_family = AF_INET;
        peer.sin_port = htons(port);
        peer.sin_addr.s_addr = inet_addr(ip.c_str());
        int n = sendto(socketfd, ret.c_str(), ret.size(), 0, (struct sockaddr *)&peer, sizeof(peer));
    }
}
// demo2
void execCommand(int socketfd, string ip, uint16_t port, string cmd)
{
    if (cmd == "rm" || cmd == "mv")
    {
        cout << "非法命令" << endl;
        exit(2);
    }
    FILE *fp = popen(cmd.c_str(), "r");
    string ret;
    if (fp == nullptr)
        ret += "fp open error";
    char line[1024];
    while (fgets(line, sizeof line, fp))
    {
        ret += line;
    }
    pclose(fp);
    // 开始返回
    struct sockaddr_in Server;
    Server.sin_family = AF_INET;
    Server.sin_port = htons(port);
    Server.sin_addr.s_addr = inet_addr(ip.c_str());
    sendto(socketfd, ret.c_str(), ret.size(), 0, (struct sockaddr *)&Server, sizeof Server);
}
// demo3
struct user
{
    string _ip;
    uint16_t _port;
};
class OnlineUsers
{
public:
    OnlineUsers()
    {
    }
    ~OnlineUsers()
    {
    }
    void ToOnline(string ip, uint16_t port)
    {
        struct user User;
        User._ip = ip;
        User._port = port;
        string name = ip+ "--" + to_string(port);
        users.insert(make_pair(name,User));
    }
    void offline(string ip,uint16_t port)
    {
        if(!IsOnline(ip,port))
        {
            return;
        }
        string name = ip+ "--" + to_string(port);
        unordered_map<string,user>::iterator it = users.find(name);
        users.erase(it);
    }
    bool IsOnline(string ip,uint16_t port)
    {
        string name = ip+ "--" + to_string(port);
        unordered_map<string,user>::iterator it = users.find(name);
        return it != users.end();
    }
    void BroadcastMessage(int socketfd, string ip, uint16_t port,string message)
    {
        for(auto& e : users)
        {
            struct sockaddr_in peer;
            peer.sin_addr.s_addr = inet_addr(e.second._ip.c_str());
            peer.sin_port = htons(e.second._port);
            peer.sin_family = AF_INET;
            string s = ip + "-" + to_string(port) +"# ";
            s+=message;
            sendto(socketfd,s.c_str(),s.size(),0,(sockaddr*)&peer,sizeof(peer));
        }
    }
private:
    unordered_map<string,user> users;
};
class OnlineUsers op;
void routeMessage(int socketfd, string ip, uint16_t port, string message)
{
    if(message == "online") op.ToOnline(ip,port);
    if(message == "offline") op.offline(ip,port);
    if(op.IsOnline(ip,port))
    {
        op.BroadcastMessage(socketfd,ip,port,message);
    }
    else
    {
        //单独发信息叫他上线
        string message = "你还没上线，请输入online以上线";
        struct sockaddr_in Client;
        Client.sin_family = AF_INET;
        Client.sin_port = htons(port);
        Client.sin_addr.s_addr = inet_addr(ip.c_str());
        sendto(socketfd,message.c_str(),message.size(),0,(struct sockaddr*)&Client,sizeof(Client));
    }
}
int main(int argv, char *argc[])
{
    if (argv != 2)
    {
        cout << "传入 port" << endl;
        exit(2);
    }
    // Lorddict();
    uint16_t port = atoi(argc[1]);
    unique_ptr<udpServer> udS(new udpServer(routeMessage, port));
    udS->Init();
    udS->start();
    return 0;
}
